package com.cw.auth.domain.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSON;
import com.cw.auth.common.enums.AuthUserStatusEnum;
import com.cw.auth.domain.constants.AuthConstant;
import com.cw.auth.domain.convert.AuthUserConvert;
import com.cw.auth.domain.entity.AuthUserBO;
import com.cw.auth.domain.redis.RedisUtil;
import com.cw.auth.domain.service.AuthUserDomainService;
import com.cw.auth.infra.basic.entity.*;
import com.cw.auth.infra.basic.service.*;
import com.cw.auth.common.enums.IsDeletedFlagEnum;
import com.google.gson.Gson;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Description:
 *
 * @Author:
 * @Date: 2024/4/27 20:35
 */
@Service
@Slf4j
public class AuthUserDomainServiceImpl implements AuthUserDomainService {
    @Resource
    private AuthUserService authUserService;
    @Resource
    private AuthUserRoleService authUserRoleService;
    @Resource
    private AuthRoleService authRoleService;
    @Resource
    private AuthPermissionService authPermissionService;
    @Resource
    private AuthRolePermissionService authRolePermissionService;
    @Resource
    private RedisUtil redisUtil;
    private final String authPermissionPrefix = "auth.permission";
    private final String authRolePrefix = "auth.role";
    private final String salt = "justinwen";
    private static final String LOGIN_PREFIX = "loginCode";

    /**
     * @author: 江传文
     * @date: 2024/4/27 21:38
     * 用户注册
     */
    @Override
    @Transactional(rollbackFor = Exception.class) // 开启事务
    @SneakyThrows
    public Boolean register(AuthUserBO authUserBO) {
        // (BO -> Entity)
        AuthUser authUser = AuthUserConvert.INSTANCE
                .convertBoToEntity(authUserBO); // 通过BO转化为Entity
        // password不为空时加密
        if (StringUtils.isBlank(authUser.getPassword())) {
            authUser.setPassword(SaSecureUtil.md5BySalt(authUser.getPassword(), salt)); // md5加盐的方式对密码进行加密
        }
        authUser.setStatus(AuthUserStatusEnum.OPEN.getCode()); // 设置用户状态为: 启用
        authUser.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode()); // 设置is_deleted字段为0(未删除)
        Integer count = authUserService.insert(authUser);
        // 建立一个初步的角色的关联
        AuthRole authRole = new AuthRole();
        authRole.setRoleKey(AuthConstant.NORMAL_USER);
        AuthRole roleResult = authRoleService.queryByCondtion(authRole);
        Integer roleId = roleResult.getId();
        // 设置insert时获取自增主键(否则这里获取到的是空)
        Integer userId = authUser.getId();
        AuthUserRole authUserRole = new AuthUserRole();
        authUserRole.setUserId(userId);
        authUserRole.setRoleId(roleId);
        authUserRole.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());
        authUserRoleService.insert(authUserRole);
        // 把当前用户的角色和权限都刷到redis中
        String roleKey = redisUtil.buildKey(authRolePrefix, authUser.getUserName());
        List<AuthRole> roleList = new LinkedList<>();
        roleList.add(authRole);
        redisUtil.set(roleKey, new Gson().toJson(roleList));

        AuthRolePermission authRolePermission = new AuthRolePermission();
        authRolePermission.setRoleId(roleId);
        List<AuthRolePermission> authRolePermissionList =
                authRolePermissionService.queryByCondition(authRolePermission);
        List<Integer> permissionIdList = authRolePermissionList.stream()
                .map(AuthRolePermission::getPermissionId).collect(Collectors.toList());
        // 根据roleId查权限
        List<AuthPermission> permissionList = authPermissionService.queryByRoleList(permissionIdList);
        String permissionKey = redisUtil.buildKey(authPermissionPrefix, authUser.getUserName());
        redisUtil.set(permissionKey, new Gson().toJson(permissionList));

        return count > 0;
    }

    /**
     * @author: 江传文
     * @date: 2024/4/27 21:38
     * 更新用户信息
     */
    @Override
    public Boolean update(AuthUserBO authUserBO) {
        // (BO -> Entity)
        AuthUser authUser = AuthUserConvert.INSTANCE
                .convertBoToEntity(authUserBO); // 通过BO转化为Entity
//        authUser.setStatus(AuthUserStatusEnum.OPEN.getCode()); // 设置用户状态为: 启用
//        authUser.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode()); // 设置is_deleted字段为0(未删除)
        Integer count = authUserService.update(authUser);
        // 有任何的更新都要与缓存进行同步的修改
        return count > 0;
    }

    @Override
    public Boolean delete(AuthUserBO authUserBO) {
        // (BO -> Entity)
        AuthUser authUser = AuthUserConvert.INSTANCE
                .convertBoToEntity(authUserBO); // 通过BO转化为Entity
        authUser.setIsDeleted(IsDeletedFlagEnum.DELETED.getCode()); // 逻辑删除
        int count = authUserService.update(authUser);
        return count > 0;
    }

    @Override
    public Boolean changeStatus(AuthUserBO authUserBO) {
        // (BO -> Entity)
        AuthUser authUser = AuthUserConvert.INSTANCE
                .convertBoToEntity(authUserBO); // 通过BO转化为Entity
        authUser.setStatus(authUserBO.getStatus());
        int count = authUserService.update(authUser);
        return count > 0;
    }

    @Override
    public AuthUserBO getUserInfo(AuthUserBO authUserBO) {
        // (BO -> Entity)
        AuthUser authUser = AuthUserConvert.INSTANCE
                .convertBoToEntity(authUserBO); // 通过BO转化为Entity

        // 查询未删除的结果(该条件会存在where条件内)
        authUser.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());

        AuthUser authUser1 = authUserService.queryByUserName(authUser);

        return AuthUserConvert.INSTANCE.convertEntityToBo(authUser1);
    }

    @Override
    public SaTokenInfo doLogin(String validCode) {
        String loginKey = redisUtil.buildKey(LOGIN_PREFIX, validCode);
        String openId = redisUtil.get(loginKey);
        if (StringUtils.isBlank(openId)) {
            return null;
        }
        AuthUserBO authUserBO = new AuthUserBO();
        authUserBO.setUserName(openId);
        this.register(authUserBO);
        StpUtil.login(openId);
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        return tokenInfo;
    }

}
